import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
  Alert,
  Breadcrumb,
  Container,
  Form,
  Row,
  Col,
  Spinner,
  Button,
  InputGroup,
  FormControl,
} from 'react-bootstrap';
import queryString from 'query-string';
import $ from 'jquery';

import { 
  URL,
  TASKDETAIL_FROM,
  TaskStatus
} from '../../config';

import { function_list_servs } from '../../actions/servs';
import {
  function_get_branches_by_servsid, 
  function_add_task,
  function_add_task_from_trash,
  function_save_task,
  function_save_task_from_trash,
} from '../../actions/deploy';
import { function_get_task } from '../../actions/task';
import { function_get_project } from '../../actions/project';

import './less/add.css';
require("select2");

class App extends Component {

  state = {
    pid: parseInt(queryString.parse(this.props.location.search).pid),
    tid: parseInt(queryString.parse(this.props.location.search).tid),
    markContent: "",
    hasError: false,
    errorMsg: "",
    validated: false,
    selectedServs: [], //需要上线的微服务
    ServsBranchSt: {}, //该微服务获取分支的状态
    servsArr: {},
    servsJobSt: {}
  }

  setValidated (validated) {
    this.setState({
      validated
    });
  }

  componentDidMount () {
    this.getProject();
    this.listServs((data)=>{
      $(this.refs.servsId).on('change.select2', this.getBranches.bind(this));
      if(this.state.tid>0) {
        this.getTask();
      }
    });
  }

  getTask(){
    function_get_task(this.state.pid, this.state.tid, this.props.dispatch, (data)=>{
      let servsJobSt = {};
      let servsArr = [];
      let servsArr2 = {};
      for(let item of this.props.taskServs){
        let servsId = item.servsId;
        servsJobSt[servsId] = [];
        let jobArr = item.jobsCommand;
        for(let jobRow of jobArr){
          servsJobSt[servsId].push({
            type: jobRow.operateType,
            name: jobRow.name,
            script: jobRow.script == null ? "" : jobRow.script,
            args: jobRow.args == null ? "" : jobRow.args,
            interpreter: jobRow.interpreter == null ? "" : jobRow.interpreter,
          });
        }
        if(servsJobSt[servsId].length === 0){
          servsJobSt[servsId] = [{
            type: 0,
            name: "",
            script: "",
            args: "",
            interpreter: "",
          }];
        }
        servsArr.push(servsId);
        servsArr2[servsId] = item;
      }
      $(this.refs.servsId).val(servsArr).trigger('change');
      this.props.admin !== null && $(this.refs.admin).val(this.props.admin.uid).trigger('change');
      this.props.tester !== null && $(this.refs.tester).val(this.props.tester.uid).trigger('change');
      this.setState({ 
        selectedServs: servsArr, 
        servsArr: servsArr2,
        servsJobSt
      });
    });
  }

  getBranches(){
    let servsArr = $(this.refs.servsId).val();
    let servsJobSt = this.state.servsJobSt;
    let ServsBranchSt = {};
    for (let servsId of servsArr) {
      if(!(servsId in servsJobSt)){
        servsJobSt[servsId] = [{
          type: 0,
          name: "",
          script: "",
          args: "",
          interpreter: "",
        }];
      }
      if (this.props.servsList[servsId].list.length === 0) {
        ServsBranchSt[servsId] = false;
        function_get_branches_by_servsid(this.props.deployUrl, servsId, this.props.dispatch, (list) => {
          ServsBranchSt[servsId] = true;
          this.setState({ ServsBranchSt: ServsBranchSt });
          this.initBranchList(servsId, list);
        });
      }else{
        ServsBranchSt[servsId] = true;
        this.initBranchList(servsId, this.props.servsList[servsId].list);
      }
    }
    this.setState({ 
      selectedServs: servsArr, 
      ServsBranchSt: ServsBranchSt,
      servsJobSt: servsJobSt
    });
  }

  listServs(cb){
    function_list_servs(this.state.pid, this.props.dispatch, (list) => {
      let data = [];
      for (let item of list) {
        data.push({ id: item.serviceId, text: item.serviceName });
      }
      $(this.refs.servsId).select2({
        placeholder: "选择需要上线的微服务（可多选）",
        data
      });
      cb(data);
    });
  }

  getProject(){
    function_get_project(this.state.pid, this.props.dispatch, (adminArr, testerArr) => {
      let data = [];
      for (let item of adminArr) {
        data.push({ id: item.uid, text: item.nickname });
      }
      if(data.length === 0){
        this.setState({
          hasError: true,
          errorMsg: "因项目未设置上线人员，无法提交测试"
        });
        return;
      }else{
        $(this.refs.admin).select2({
          placeholder: "选择上线人员",
          data
        });
      }
      data = [];
      for (let item of testerArr) {
        data.push({ id: item.uid, text: item.nickname });
      }
      if(data.length === 0){
        this.setState({
          hasError: true,
          errorMsg: "因项目未设置测试人员，无法提交测试"
        });
        return;
      }else{
        $(this.refs.tester).select2({
          placeholder: "选择测试人员",
          data
        });
      }
    });
  }

  initBranchList(servsId, list){
    let data = [];
    for (let item of list) {
      if(item === null) continue;
      data.push({ id: item, text: item });
    }
    $(this.refs["servs" + servsId + "branch"]).select2({
      placeholder: "选择需要上线的分支",
      data,
      allowClear: true
    });
    if(this.state.tid>0 && typeof(this.state.servsArr[servsId]) != "undefined"){
      $(this.refs["servs" + servsId + "branch"]).val(this.state.servsArr[servsId].branch).trigger('change');
    }
  }

  saveTask () {
    let title = $(this.refs.title).val();
    if(title === ""){
      this.setState({
        hasError: true,
        errorMsg: "上线单标题必填"
      });
      return;
    }
    let servsIdArr = $(this.refs.servsId).val();
    if (servsIdArr.length === 0) {
      this.setState({
        hasError: true,
        errorMsg: "至少需要选择一个微服务"
      });
      return;
    }
    let realServsArr = [""];
    let realBranchArr = [""];
    let realSqlsArr = [""];
    let realJobsArr = [""];
    for (let servsId of servsIdArr) {
      let branch = $(this.refs["servs" + servsId + "branch"]).val();
      if (branch !== null && branch !== "") {
        let jobArr = this.state.servsJobSt[servsId];
        let realJobsRow = "";
        for(let job of jobArr){
          //创建job
          if(job.type === 1){
            if(job.name === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本名称必填"
              });
              return;
            }
            if(job.script === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本路径必填"
              });
              return;
            }
            if(job.interpreter === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本解释器路径必填"
              });
              return;
            }
          }else if(job.type === 2){
            if(job.name === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "重启job，脚本名称必填"
              });
              return;
            }
          }else{
            continue;
          }
          realJobsRow += job.type + "|" + job.name + "|" + job.script + "|" + job.args + "|" + job.interpreter + "@@";
        }
        realJobsArr.push(realJobsRow);
        realServsArr.push(servsId);
        realBranchArr.push(branch);
        let sqlInput = $(this.refs["servs" + servsId + "sqls"]);
        if(sqlInput.length<=0) {
          realSqlsArr.push("");
        }else{
          let sqls = sqlInput.val();
          if (sqls !== null && sqls !== "") {
            realSqlsArr.push(sqls);
          } else {
            realSqlsArr.push("");
          }
        }
      }
    }
    if (realBranchArr.length === 1) {
      this.setState({
        hasError: true,
        errorMsg: "请选择需要上线的分支"
      });
      return;
    }
    let tester = $(this.refs.tester).val();
    if (tester === null || tester === "") {
      tester = 0;
    }
    let admin = $(this.refs.admin).val();
    if (admin === null || admin === "") {
      admin = 0;
    }
    this.setState({
      hasError: false,
      errorMsg: ""
    });
    let markContent = $(this.refs.markContent).val();
    if(this.state.tid>0){
      function_save_task_from_trash(
        this.state.tid,
        this.state.pid,
        $(this.refs.title).val(),
        markContent,
        realServsArr,
        realBranchArr,
        realSqlsArr,
        realJobsArr,
        admin,
        tester,
        this.props.dispatch,
        taskId => {
          this.props.history.push(URL.trashtask_page+"?pid="+this.state.pid+"&page=1");
        }
      );
    }else{
      function_save_task(
        this.state.pid,
        $(this.refs.title).val(),
        markContent,
        realServsArr,
        realBranchArr,
        realSqlsArr,
        realJobsArr,
        admin,
        tester,
        this.props.dispatch,
        taskId => {
          this.props.history.push(URL.trashtask_page+"?pid="+this.state.pid+"&page=1");
        }
      );
    }
  }

  handleSubmit (event) {
    let servsIdArr = $(this.refs.servsId).val();
    if (servsIdArr.length === 0) {
      this.setState({
        hasError: true,
        errorMsg: "至少有一个微服务需要上线"
      });
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    let realServsArr = [""];
    let realBranchArr = [""];
    let realSqlsArr = [""];
    let realJobsArr = [""];
    for (let servsId of servsIdArr) {
      let branch = $(this.refs["servs" + servsId + "branch"]).val();
      if(this.props.servsList[servsId].targetBranch === branch){
        this.setState({
          hasError: true,
          errorMsg: this.props.servsList[servsId].name + "需要上线的分支不能是当前微服务的主分支"
        });
        event.preventDefault();
        event.stopPropagation();
        return;
      }
      if (branch !== null && branch !== "") {
        let jobArr = this.state.servsJobSt[servsId];
        let realJobsRow = "";
        for(let job of jobArr){
          //创建job
          if(job.type === 1){
            if(job.name === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本名称必填"
              });
              event.preventDefault();
              event.stopPropagation();
              return;
            }
            if(job.script === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本路径必填"
              });
              event.preventDefault();
              event.stopPropagation();
              return;
            }
            if(job.interpreter === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "创建job，脚本解释器路径必填"
              });
              event.preventDefault();
              event.stopPropagation();
              return;
            }
          }else if(job.type === 2){
            if(job.name === ""){
              this.setState({
                hasError: true,
                errorMsg: this.props.servsList[servsId].name + "重启job，脚本名称必填"
              });
              event.preventDefault();
              event.stopPropagation();
              return;
            }
          }else{
            continue;
          }
          realJobsRow += job.type + "|" + job.name + "|" + job.script + "|" + job.args + "|" + job.interpreter + "@@";
        }
        realJobsArr.push(realJobsRow);
        realServsArr.push(servsId);
        realBranchArr.push(branch);
        let sqlInput = $(this.refs["servs" + servsId + "sqls"]);
        if(sqlInput.length<=0) {
          realSqlsArr.push("");
        }else{
          let sqls = sqlInput.val();
          if (sqls !== null && sqls !== "") {
            realSqlsArr.push(sqls);
          } else {
            realSqlsArr.push("");
          }
        }
      }
    }
    if (realBranchArr.length === 1) {
      this.setState({
        hasError: true,
        errorMsg: "请选择需要上线的分支"
      });
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    let tester = $(this.refs.tester).val();
    if (tester === null || tester === "") {
      this.setState({
        hasError: true,
        errorMsg: "需要填写测试人员"
      });
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    let admin = $(this.refs.admin).val();
    if (admin === null || admin === "") {
      this.setState({
        hasError: true,
        errorMsg: "需要填写上线人员"
      });
      event.preventDefault();
      event.stopPropagation();
      return;
    }
    this.setState({
      hasError: false,
      errorMsg: ""
    });

    const form = event.currentTarget;
    if (form.checkValidity() === false) {
      event.preventDefault();
      event.stopPropagation();
    }
    this.setValidated(true);
    let markContent = $(this.refs.markContent).val();
    if(this.state.tid>0){
      function_add_task_from_trash(
        this.state.tid,
        this.state.pid,
        $(this.refs.title).val(),
        markContent,
        realServsArr,
        realBranchArr,
        realSqlsArr,
        realJobsArr,
        admin,
        tester,
        this.props.dispatch,
        taskId => {
          this.props.history.push(URL.taskdetail_page+"?pid="+this.state.pid+"&tid="+taskId+"&from="+TASKDETAIL_FROM.ADDTASK);
        }
      );
    }else{
      function_add_task(
        this.state.pid,
        $(this.refs.title).val(),
        markContent,
        realServsArr,
        realBranchArr,
        realSqlsArr,
        realJobsArr,
        admin,
        tester,
        this.props.dispatch,
        taskId => {
          this.props.history.push(URL.taskdetail_page+"?pid="+this.state.pid+"&tid="+taskId+"&from="+TASKDETAIL_FROM.ADDTASK);
        }
      );
    }
    event.preventDefault();
    event.stopPropagation();
  }

  render () {
    return (
      <Container>
        <Breadcrumb>
          <Breadcrumb.Item href={URL.main_page}>项目列表</Breadcrumb.Item>
          <Breadcrumb.Item href={URL.project_page + "?pid=" + this.state.pid}>项目</Breadcrumb.Item>
          <Breadcrumb.Item active>{this.state.tid>0 ? "修改上线单" : "提交上线单"}</Breadcrumb.Item>
        </Breadcrumb>
        {(Object.keys(this.props.projectList).length>0 && this.props.projectList[this.state.pid].developer.indexOf(this.props.myuid)>-1) ? 
          (this.state.hasError ?
            <Alert variant="danger" onClose={() => this.setState({hasError: false, errorMsg: ""})} dismissible>
              {this.state.errorMsg}
            </Alert>
          : null)
        :
        <Alert variant="danger" onClose={() => this.setState({hasError: false, errorMsg: ""})}>
          仅开发人员有权提交上线单
        </Alert>
        }
        <Row>
          <Col sm={8}>
            <Form className="taskAddForm" noValidate validated={this.state.validated} onSubmit={this.handleSubmit.bind(this)}>
              <Form.Group as={Row}>
                <Form.Label column sm="3">
                  标题
                </Form.Label>
                <Col sm="9">
                  <Form.Control
                    ref="title"
                    placeholder="简单说一下本次上线的功能，方便他人理解 必填"
                    defaultValue={this.state.tid>0 ? this.props.taskName : ""}
                    required />
                  <Form.Control.Feedback type="invalid">
                    请填写上线单名称
                  </Form.Control.Feedback>
                </Col>
              </Form.Group>
              <Form.Group as={Row}>
                <Form.Label column sm="3">
                  需要上线的微服务
                </Form.Label>
                <Col sm="9">
                  <Form.Control ref="servsId" as="select" multiple="multiple" />
                </Col>
              </Form.Group>
            {this.state.selectedServs.map(servsId => {
              let item = this.props.servsList[servsId];
              let config = servsId in this.state.servsArr ? this.state.servsArr[servsId] : false;
              return (
                <fieldset className="serverBox" key={servsId}>
                  <legend>{item.name}</legend>
                  <Form.Group as={Row}>
                    <Form.Label column sm="3">
                      需要上线的分支
                    </Form.Label>
                    <Col sm="9" style={{textAlign: !this.state.ServsBranchSt[servsId] ? "center" : "inherit"}}>
                      {this.state.ServsBranchSt[servsId] ? 
                        <Form.Control ref={"servs" + servsId + "branch"} as="select" defaultValue={config?config.branch:0} />
                      : <Spinner animation="border" />}
                    </Col>
                  </Form.Group>
                  <Form.Group as={Row}>
                    <Form.Label column sm="3">
                      需要执行的sql语句
                    </Form.Label>
                    <Col sm="9">
                      <Form.Control
                        ref={"servs" + servsId + "sqls"}
                        as="textarea"
                        placeholder="非必填 sql语句需要使用英文;号分割 sql语句必须带有数据库名"
                        rows="5"
                        className="textarea-code"
                        defaultValue={config ? config.sqls.join(";\n") :""} />
                      { item.lineDb === "" ? 
                        <Form.Text className="text-danger">
                          由于项目管理员未配置该微服务的线上数据库，上线时需提醒上线人员手动执行以上sql语句
                        </Form.Text>  
                      : null }
                    </Col>
                  </Form.Group>
                  <fieldset>
                    <legend>job操作</legend>
                  {this.state.servsJobSt[servsId].map((jobRow, indexJobRow) => {
                    return (
                      <Form.Row key={indexJobRow}>
                        <Col className="col-sm-2">
                          <Form.Control as="select" value={jobRow.type} onChange={
                            event => {
                              jobRow.type = parseInt($(event.target).val());
                              let servsJobSt = this.state.servsJobSt;
                              servsJobSt[servsId][indexJobRow] = jobRow;
                              this.setState({ servsJobSt });
                            }
                          }>
                            <option value="0">无操作</option>
                            <option value="1">创建job</option>
                            <option value="2">重启job</option>
                          </Form.Control>
                        </Col>
                        <Col>
                          {jobRow.type === 1 ?
                          <InputGroup>
                            <FormControl
                              placeholder="脚本名称"
                              value={jobRow.name}
                              onChange={
                                event => {
                                  jobRow.name = $(event.target).val();
                                  let servsJobSt = this.state.servsJobSt;
                                  servsJobSt[servsId][indexJobRow] = jobRow;
                                  this.setState({ servsJobSt });
                                }
                              }
                              />
                            <FormControl 
                              placeholder="脚本路径" 
                              value={jobRow.script}
                              onChange={
                                event => {
                                  jobRow.script = $(event.target).val();
                                  let servsJobSt = this.state.servsJobSt;
                                  servsJobSt[servsId][indexJobRow] = jobRow;
                                  this.setState({ servsJobSt });
                                }
                              }
                              />
                            <FormControl
                              placeholder="脚本参数"
                              value={jobRow.args}
                              onChange={
                                event => {
                                  jobRow.args = $(event.target).val();
                                  let servsJobSt = this.state.servsJobSt;
                                  servsJobSt[servsId][indexJobRow] = jobRow;
                                  this.setState({ servsJobSt });
                                }
                              }
                              />
                            <FormControl
                              placeholder="脚本解释器路径"
                              value={jobRow.interpreter}
                              onChange={
                                event => {
                                  jobRow.interpreter = $(event.target).val();
                                  let servsJobSt = this.state.servsJobSt;
                                  servsJobSt[servsId][indexJobRow] = jobRow;
                                  this.setState({ servsJobSt });
                                }
                              }
                              />
                          </InputGroup>
                          :null}
                          {jobRow.type === 2 ?
                          <InputGroup>
                            <FormControl
                              placeholder="脚本名称"
                              value={jobRow.name}
                              onChange={
                                event => {
                                  jobRow.name = $(event.target).val();
                                  let servsJobSt = this.state.servsJobSt;
                                  servsJobSt[servsId][indexJobRow] = jobRow;
                                  this.setState({ servsJobSt });
                                }
                              }
                              />
                          </InputGroup>
                          :null}
                        </Col>
                        <Col className="col-sm-1">
                          {(indexJobRow+1) === this.state.servsJobSt[servsId].length ? 
                            (jobRow.type > 0 ?
                            <Button variant="outline-primary" onClick={()=>{
                              let servsJobSt = this.state.servsJobSt;
                              servsJobSt[servsId].push({
                                type: 0,
                                name: "",
                                script: "",
                                args: "",
                                interpreter: "",
                              });
                              this.setState({ servsJobSt });
                            }}>+</Button>
                            :
                            <Button variant="outline-primary" onClick={()=>{
                              let servsJobSt = this.state.servsJobSt;
                              servsJobSt[servsId].pop();
                              this.setState({ servsJobSt });
                            }}>-</Button>
                            )
                          :null}
                        </Col>
                      </Form.Row>
                    )
                  })}
                  </fieldset>
                </fieldset>
              )
            })}
              <Form.Group as={Row}>
                <Form.Label column sm="3">
                  备注信息
                </Form.Label>
                <Col sm="9">
                  <Form.Control
                    ref="markContent"
                    as="textarea"
                    placeholder="如 crontab、注意事项等"
                    rows="5"
                    defaultValue={this.props.markContent} />
                </Col>
              </Form.Group>
              <Form.Group as={Row}>
                <Form.Label column sm="3">
                  测试人员
                </Form.Label>
                <Col sm="9">
                  <Form.Control ref="tester" as="select" disabled={this.state.tid > 0 && this.props.deployStatus !== TaskStatus.WAIT_FOR_SUBMIT} />
                </Col>
              </Form.Group>
              <Form.Group as={Row}>
                <Form.Label column sm="3">
                  上线人员
                </Form.Label>
                <Col sm="9">
                  <Form.Control ref="admin" as="select" disabled={this.state.tid > 0 && this.props.deployStatus !== TaskStatus.WAIT_FOR_SUBMIT} />
                </Col>
              </Form.Group>
              {(Object.keys(this.props.projectList).length>0 && this.props.projectList[this.state.pid].developer.indexOf(this.props.myuid)>-1) ? 
                (this.state.tid > 0 && this.props.deployStatus !== TaskStatus.WAIT_FOR_SUBMIT ? 
                  <Col sm={{ span: 7, offset: 3 }}>
                    <Button type="submit" variant="primary">保存修改</Button>
                  </Col>
                :
                <Col sm={{ span: 7, offset: 3 }}>
                  <Button variant="outline-secondary" onClick={this.saveTask.bind(this)}>保存草稿</Button>
                  {!this.state.hasError ? <Button type="submit" variant="success">提交测试</Button> : null}
                </Col>
                )
              :null}
            </Form>
          </Col>
          <Col sm={4}>
            <ul>
              <li>需要上线的微服务</li>
              <p>
                多选，选出您本次版本开发所涉及到的微服务。选完后，您需要选择该微服务合并到主分支的分支。若管理员为该微服务配置了线上数据库的链接，您可以将该微服务对应数据库需要执行的sql语句粘贴到这里，分支合并完成后，上线工具会自动执行这些sql语句。
              </p>
              <li>需要执行的sql语句</li>
              <p>
                【重要】：sql语句的表名前需要带上数据库名
              </p>
              <li>保存草稿</li>
              <p>
                如果您还没打算通知测试人员进行测试，那就 保存草稿 吧！
              </p>
            </ul>
          </Col>
        </Row>  
      </Container>
    )
  }
}

function mapStateToProps (state) {
  return {
    myuid: state.account.uid,
    taskName: state.tasks.taskName,
    markContent: state.tasks.markContent,
    deployStatus: state.tasks.deployStatus,
    admin: state.tasks.admin,
    tester: state.tasks.tester,
    deployUrl: state.deploy.deployUrl,
    servsList: state.servs,
    taskServs: state.tasks.serversList,
    projectList: state.project,
  }
}

export default connect(mapStateToProps)(App);